﻿/**             © 2008 Avanade Inc. All Rights Reserved.
 * 
 * Authors:     Joris Valkonet joris.valkonet@avanade.com  Avanade Netherlands
 *              Thanh Luc      thanh.luc@avanade.com       Avanade Netherlands
 *              Mark Beerens   mark.beerens@avanade.com    Avanade Netherlands
 * 
 * Content:     This is the base class of the viewer and therefore implements the 
 *              IMiningModelViewerControl for the basic functionality and the 
 *              IMiningModelViewerControl2 interface for Excel functionality
 *                 
 * */

#region [Using]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

using System.Collections;
using System.Data.OleDb;
using Microsoft.DataWarehouse.Interfaces;
//using System.Diagnostics;
using System.Drawing.Drawing2D;
#endregion
namespace Avanade.Datamining.SVMPluginViewer
{
    public partial class SVMViewerUserControl : UserControl, IMiningModelViewerControl, IMiningModelViewerControl2
    {

        #region [Parameters]
        //the colors of the predict values
        private SortedDictionary<String, Color> ValueColors = new SortedDictionary<String, Color>();
        //the color of a misclassification
        private Color misclassifiedColor = Color.Red;
        //did the user click on load already?
        private bool loaded = false;
        //do we need to show the misclassifications
        private bool showClassifier = true;
        //the selected data for visualization: [Trainingdata, TestData];
        private String data = "Trainingdata";
        //the selected column on the x-axis
        public string x_name;
        //the selected column on the y-axis
        public string y_name;
        //do we need to draw the axes
        private Boolean drawAxes = true;

        #endregion

        #region [Loading]
        /// <summary>
        /// Constructor.. This does nothing special, but initialization
        /// </summary>
        public SVMViewerUserControl()
        {
            InitializeComponent();
            BackColor = Color.White;
            // hide the following text labels
            this.label_X_Axis.Hide();
            this.label_Y_Axis.Hide();

            //set default values for display and grid options
            comboBox4.Text = "Yes";
            checkBox1.Checked = showClassifier;
            comboBox6.Text = "Trainingdata";
            //make sure that 2005 won't get into trouble.
            if (version != "2008")
            {
                comboBox6.Enabled = false;
            }
        }

        /// <summary>
        /// /...
        /// </summary>
        /// <param name="isActivated"></param>
        public void ViewerActivated(bool isActivated)
        {

        }

        /// <summary>
        /// This method is automatically executed by the host
        /// it loads the basic information into the model
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public bool LoadViewerData(object obj)
        {
            //get the min and max values
            getMinMaxValues();
            //get the input attributes
            getAttributes();
            //set the predict classes

            setClasses();
            BindingSource source1 = new BindingSource();
            source1.DataSource = inputAttributes.Keys;
            BindingSource source2 = new BindingSource();
            source2.DataSource = inputAttributes.Keys;

            comboBox1.DataSource = source1;
            comboBox2.DataSource = source2;
            if (comboBox2.Items.Count > 1)
            {
                comboBox2.SelectedIndex = 1;
            }


            comboBox1.Refresh();
            comboBox2.Refresh();
            this.predict_name = getPredictAttribute();
            textBox1.Text = predict_name;
            textBox1.Refresh();
            button2.BackColor = misclassifiedColor;
            button2.Refresh();
            return true;
        }

        /// <summary>
        /// This method loads the data into the viewer. We have added a button for this, because
        /// loading the data can take a lot of time...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button4_Click(object sender, EventArgs e)
        {
            loaded = true;
            button4.Hide();
            RedrawScatterplot();
        }


        /// <summary>
        /// THis method assigns the colors to the predict values and loads the
        /// predict values in the combobox
        /// </summary>
        private void setClasses()
        {
            //get the classes and assign a color to each class
            String [] classes = getClasses();
            int i = 0;
            foreach (string value in classes)
            {
                switch (i)
                {
                    case 0: ValueColors.Add(value, Color.ForestGreen); break;
                    case 1: ValueColors.Add(value, Color.Blue); break;
                    case 2: ValueColors.Add(value, Color.Green); break;
                    case 3: ValueColors.Add(value, Color.Black); break;
                    case 4: ValueColors.Add(value, Color.Yellow); break;
                    case 5: ValueColors.Add(value, Color.Purple); break;
                    case 6: ValueColors.Add(value, Color.Chocolate); break;
                    case 7: ValueColors.Add(value, Color.DarkOliveGreen); break;
                    case 8: ValueColors.Add(value, Color.FloralWhite); break;
                    default:
                        {
                            Random rnd = new Random();
                            ValueColors.Add(value, Color.FromArgb(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255))); 
                            break;
                        }
                }
                i++;
                
            }

            //load the classes in the combobox
            comboBox3.DataSource = classes;
            comboBox3.Refresh();
            Color tmpColor;
            ValueColors.TryGetValue(comboBox3.Text, out tmpColor);
            button1.BackColor = tmpColor;
        }
        #endregion

        #region [Redraw]
        /// <summary>
        /// This method redraw the scatter plot, after a value has changed somewhere
        /// but.. only when the user has clicked on the load button...
        /// </summary>
        private void RedrawScatterplot()
        {
            if (loaded)
            {
                if (this.comboBox1.Text == this.comboBox2.Text)
                {   // Check whether the X and Y comboboxes contain the same value

                    MessageBox.Show("The X and Y should not be assigned the same attribute.");
                }
                else
                {
                    // Turn mouse pointer into hourglass
                    Cursor.Current = Cursors.WaitCursor;

                    this.x_name = this.comboBox1.Text;
                    this.y_name = this.comboBox2.Text;
                    this.predict_name = this.textBox1.Text;
                    String x_type;
                    String y_type;
                    inputAttributes.TryGetValue(x_name, out x_type);
                    inputAttributes.TryGetValue(y_name, out y_type);
                    this.GetTrainingData();

                    //determine the types of the selected columns and
                    //the viewer shown depends on the types of the 
                    //attributes
                    if (x_type == "Continuous" && y_type == "Continuous")
                    {
                        //get the min and max values
                        maxValues.TryGetValue(x_name, out maxX);
                        minValues.TryGetValue(x_name, out minX);
                        maxValues.TryGetValue(y_name, out maxY);
                        minValues.TryGetValue(y_name, out minY);
                        
                        // Execute Paint 
                        Paint += new PaintEventHandler(OnPaint);

                        // Refresh user control to redraw itself
                        this.Refresh();

                    }
                    else if (x_type == "Discrete" && y_type == "Discrete")
                    {
                        //draw the bars
                        Paint += new PaintEventHandler(OnDiscretePaint);
                        this.Refresh();
                    }
                    else if (x_type == "Discrete") //and y continuous
                    {
                        MessageBox.Show("In this version of the viewer the combination of a discrete and continuous attribute is not supported by a visualization", "Sorry");
                    }
                    else
                    {
                        //continuous versus discrete
                        MessageBox.Show("In this version of the viewer the combination of a discrete and continuous attribute is not supported by a visualization", "Sorry");
                    }

                    // Set names for Scatterplot Axes
                    this.label_X_Axis.Text = String.Format("X:  {0}", this.comboBox1.Text);
                    this.label_Y_Axis.Text = String.Format("Y:  {0}", this.comboBox2.Text);
                    this.label_X_Axis.Visible = true;
                    this.label_Y_Axis.Visible = true;
                    // Reset mouse pointer to normal
                    Cursor.Current = Cursors.Default;
                }
            }
        }

        #endregion

        #region [Control]

        /// <summary>
        /// Update de button when a different predict value is selected
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox3_SelectedIndexChanged(object sender, EventArgs e)
        {
            Color color = Color.Brown;
            if(ValueColors.TryGetValue(comboBox3.Text, out color)){
                button1.BackColor = color;
            }
            else
            {
                button1.BackColor = color;
            }
        }

        /// <summary>
        /// This method enables you to select a color for a predict value
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            //set the color of the selected class.. if it is predefined and show the color selection dialog
            if (ValueColors.ContainsKey(comboBox3.Text))
            {
                Color tmpColor = Color.Brown;
                ValueColors.TryGetValue(comboBox3.Text, out tmpColor);
                colorDialog1.Color = tmpColor;
            }
            colorDialog1.ShowDialog(this);

            //obtain the color, update the data structure and repaint the button
            button1.BackColor = colorDialog1.Color;
            if (ValueColors.ContainsKey(comboBox3.Text))
            {
                ValueColors.Remove(comboBox3.Text );
            }
            ValueColors.Add(comboBox3.Text, colorDialog1.Color);

            //repaint
            RedrawScatterplot();
        }

        /// <summary>
        /// This method can change the color of the misclassifications
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            //set de misclassification color in the colordialog and show the diaglog
            colorDialog1.Color = misclassifiedColor;
            colorDialog1.ShowDialog(this);
            //ask the misclassification color from the dialog and repaint the button
            misclassifiedColor = colorDialog1.Color;
            button2.BackColor = misclassifiedColor;

            //repaint
            RedrawScatterplot();
        }

        /// <summary>
        /// This method redraws the scatter plot when different attributes are chosen
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            RedrawScatterplot();
        }

        /// <summary>
        /// This methode redraws the scatter plot when different attribtues are chosen
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            RedrawScatterplot();
        }

        /// <summary>
        /// The method redraws the scatter plot when different display is chosen
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox5_SelectedIndexChanged(object sender, EventArgs e)
        {
            RedrawScatterplot();
        }

        /// <summary>
        /// this method redraws the scatter plot when a different grid option is chosen
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox4_SelectedIndexChanged(object sender, EventArgs e)
        {
            RedrawScatterplot();
        }

        /// <summary>
        /// Show classifier is changes
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            showClassifier = checkBox1.Checked;
            RedrawScatterplot();
        }

        /// <summary>
        /// The type of data is changed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox6_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!comboBox6.Text.Equals(data))
            {
                if (comboBox6.Text.Equals("Testingdata"))
                {
                    data = "Testingdata";
                }
                else
                {
                    data = "Trainingdata";
                }
                RedrawScatterplot();
            }
        }

        /// <summary>
        /// Displays the accuracy of the selected data
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button3_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Trainingset accuracy: " + getTrainingAccuracy() + "\n Testset accuracy: " + getTestAccuracy(), "Dataset details");
        }
        #endregion
    } 
}
